package com.gmrz.uas.plugin.faceprint;

import com.gmrz.uas.plugin.authservice.AuthServiceConfigSpec;
import com.gmrz.uas.plugin.authservice.AuthServiceData;
import com.gmrz.uas.plugin.authservice.AuthServiceDataSpec;
import com.gmrz.uas.plugin.authservice.BaseAuthServicePlugin;
import com.gmrz.uas.plugin.exception.AuthNoMatchPluginBusinessException;
import com.gmrz.uas.plugin.exception.PluginException;
import com.gmrz.uas.plugin.util.HttpClientUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by gongyuqiang on 2017/5/25.
 */
public class DefaultFaceprintAuthService extends BaseAuthServicePlugin {
    private static final Logger LOG = LogManager.getLogger(DefaultFaceprintAuthService.class);
    public static final String CONFIG_KEY_APPKEY = "appKey";
    public static final String CONFIG_KEY_SECRET = "appSecret";
    public static final String CONFIG_KEY_SERVER_HOST = "host";
    public static final String CONFIG_KEY_SERVER_PORT = "port";
    public static final String CONFIG_KEY_CONFIDENCE = "confidence";

    public static final String CONTENT_ID_PHOTO = "photo";

    public DefaultFaceprintAuthService(){
        this.allConfig = new HashMap<String, String>();

        this.allConfigSpec = new HashMap<String, AuthServiceConfigSpec>();
        this.allConfigSpec.put(CONFIG_KEY_APPKEY, new AuthServiceConfigSpec("", ""));
        this.allConfigSpec.put(CONFIG_KEY_SECRET, new AuthServiceConfigSpec("", ""));
        this.allConfigSpec.put(CONFIG_KEY_SERVER_PORT, new AuthServiceConfigSpec("", ""));
        this.allConfigSpec.put(CONFIG_KEY_SERVER_HOST, new AuthServiceConfigSpec("", ""));
        this.allConfigSpec.put(CONFIG_KEY_CONFIDENCE, new AuthServiceConfigSpec("", ""));

        this.allDataSpec = new HashMap<String, AuthServiceDataSpec>();
        this.allDataSpec.put(CONTENT_ID_PHOTO, new AuthServiceDataSpec().withSupprotPersistent(true));

    }

    private String signData(String appKey, String appSecret, String clienttime, String transactionno){
        StringBuilder builder = new StringBuilder();
        builder.append(appSecret);
        builder.append(appKey);
        builder.append(clienttime);
        builder.append(transactionno);
        builder.append(appSecret);

        return CryptoUtil.getMD5Digest(builder.toString());

    }

    /**
     * 注册人脸
     * @param username
     * @param contents
     * @throws PluginException
     */
    @Override
    public void register(String username, List<AuthServiceData> contents) throws PluginException{
        LOG.info("DefaultFaceprintAuthService register begin username:"+username);
        Connection conn = null;
        PreparedStatement s = null;
        ResultSet rs = null;
        try {
            if(contents == null || contents.isEmpty()){
                LOG.error("contents is empty");
                throw new PluginException("invalid params for registration ");
            }
            AuthServiceData content = contents.get(0);
            if(content.getId() == null || content.getContent() == null)
                throw new PluginException("invalid params for registration ");

            unregister(username);
            int offset = 1;
            conn = this.uasServiceProvider.getUasConnection(false);
            String sql = "INSERT INTO t_faceprint_data (username,face_data) VALUES (?,?) ";
            s = conn.prepareStatement(sql, 1);
            s.setString(offset++, username);
            s.setString(offset++, this.uasServiceProvider.toBase64String(CryptoUtil.bcAes256Decode(content.getContent(),CryptoUtil.getSHA256(content.getKey()))));

            s.executeUpdate();

            conn.commit();

        }catch (SQLException sqle) {
            LOG.error("Failed to  connect to database, ", sqle);
            throw new PluginException("Failed to connect to database");
        }
        catch (Exception e){
            e.printStackTrace();
            LOG.error(e);
            throw new PluginException("Filed to register");
        }finally {
            close(s);
            close(rs);
            close(conn);
            LOG.info("DefaultFaceprintAuthService register end");
        }
    }

    /**
     * 认证人脸
     * @param username
     * @param contents
     * @throws PluginException
     */
    @Override
    public void authenticate(String username, List<AuthServiceData> contents) throws PluginException{
        LOG.info("DefaultFaceprintAuthService authenticate begin username:"+username);
        Connection conn = null;
        PreparedStatement s = null;
        ResultSet rs = null;
        try {
            if(contents == null || contents.isEmpty()){
                LOG.error("contents is empty");
                throw new PluginException("invalid params for authentication ");
            }
            AuthServiceData content = contents.get(0);
            if(content.getId() == null || content.getContent() == null)
                throw new PluginException("invalid params for authentication ");
            String photo1 = this.uasServiceProvider.toBase64String(CryptoUtil.bcAes256Decode(content.getContent(),CryptoUtil.getSHA256(content.getKey())));

            conn = this.uasServiceProvider.getUasConnection(false);
            String sql = "SELECT username, face_data FROM t_faceprint_data where username=?";
            s = conn.prepareStatement(sql);
            s.setString(1, username);
            rs = s.executeQuery();
            String data = null;
            while (rs.next()) {
                data = rs.getString("face_data");
                break;
            }
            if(data == null){
                LOG.error("can not find faceprint data for username:" + username);
                throw new PluginException("can not find faceprint data");
            }
            String photo2 = data;

            LOG.debug("!!!!photo2=" + photo2);

            String host = this.allConfig.get(CONFIG_KEY_SERVER_HOST);
            String port = this.allConfig.get(CONFIG_KEY_SERVER_PORT);
//            String postUrl = String.format("http://%s:%s/face-service/v1.0/service/face-compare", host, port);
//            String transactionno = this.uasServiceProvider.generateID();
//
//            String appKey = this.allConfig.get(CONFIG_KEY_APPKEY);
//            String appSecret = this.allConfig.get(CONFIG_KEY_SECRET);
//            Date currentTime = new Date();
//            SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
//            String clienttime = formatter.format(currentTime);
//            String sign = signData(appKey, appSecret, clienttime, transactionno);
//
//            Map<String, String> params = new HashMap<String, String>();
//            params.put("app_key", appKey);
//            params.put("client_time", clienttime);
//            params.put("transaction_no", transactionno);
//            params.put("sign", sign);
//            params.put("photo1", photo1);
//            params.put("photo2", photo2);
//
//            String response = HttpClientUtil.post(postUrl, new Gson().toJson(params), "application/json");


//            String host = "192.168.6.119";
//            String port = "8081";
            String postUrl = String.format("http://%s:%s/cv/face-comparison/1.7", host, port);
            String transactionno1 = this.uasServiceProvider.generateID();
            String transactionno2 = this.uasServiceProvider.generateID();

            String requet = "{ \"image1\":{    \"imageId\":\""+transactionno1+"\",    \"base64Data\": \""+photo1+"\"    },    \"image2\":{    \"imageId\": \""+transactionno2+"\",    \"base64Data\":\""+photo2+"\" }}";
            LOG.info("face service requet:" + requet);
            String response = HttpClientUtil.post(postUrl, requet, "application/json");



            LOG.info("face service response:" + response);

            int confidence = Integer.parseInt(this.allConfig.get(CONFIG_KEY_CONFIDENCE));
            GsonBuilder gb = new GsonBuilder();
            Gson gson = gb.create();
//            Map<String, String> result =  gson.fromJson(response, new TypeToken<Map<String,String>>(){}.getType());
//
//            if(Integer.parseInt(result.get("code")) != 0 || Integer.parseInt(result.get("score")) < confidence){
//                throw new AuthNoMatchPluginBusinessException("Faceprint Authentication failed");
//            }

            JsonParser jsonParser = new JsonParser();
            JsonElement jsonElement = jsonParser.parse(response);
            JsonElement j = jsonElement.getAsJsonObject().getAsJsonPrimitive("status");
            int status  = j.getAsInt();
            if(status == 0) {
                JsonElement result = jsonElement.getAsJsonObject().getAsJsonObject("result");
                double similarity = result.getAsJsonObject().getAsJsonPrimitive("similarity").getAsDouble();
                BigDecimal b1 = new BigDecimal(similarity);
                BigDecimal b2 = new BigDecimal(100);
                int score = b1.multiply(b2).intValue();
                if(score > confidence){

                }else {
                    throw new AuthNoMatchPluginBusinessException("Faceprint Authentication failed");
                }
            }else {
                throw new AuthNoMatchPluginBusinessException("Faceprint Authentication failed");
            }
        }catch (SQLException sqle) {
            LOG.error("Failed to  connect to database, ", sqle);
            throw new PluginException("Faceprint Authentication failed");
        }catch (AuthNoMatchPluginBusinessException e){
            throw e;
        }
        catch (Exception e){
            e.printStackTrace();
            LOG.error(e);
            throw new PluginException("Faceprint Authentication failed");
        }finally {
            close(s);
            close(rs);
            close(conn);
            LOG.info("DefaultFaceprintAuthService register end");
        }
    }

    /**
     * 注销人脸
     * @param username
     * @throws PluginException
     */
    @Override
    public void unregister(String username) throws PluginException {
        Connection conn = null;
        PreparedStatement s = null;
        try {
            conn = this.uasServiceProvider.getUasConnection(false);
            String sql = "DELETE FROM t_faceprint_data where username=?";
            s = conn.prepareStatement(sql);
            s.setString(1, username);
            s.executeUpdate();
            conn.commit();

        }catch (SQLException sqle) {
            LOG.error("Failed to  connect to database, ", sqle);
            throw new PluginException("Faceprint unregister failed");
        }
        catch (Exception e){
            e.printStackTrace();
            LOG.error(e);
            throw new PluginException("Faceprint unregister failed");
        }finally {
            close(s);
            close(conn);
            LOG.info("DefaultFaceprintAuthService register end");
        }
    }
}
